package com.bba.manager.gateway.filter;

import com.bba.manager.gateway.util.JwtUtil;
import com.bba.manager.gateway.util.ResponseEnum;
import com.bba.manager.gateway.util.ResponseVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class LoginGatewayFilterFactory extends AbstractGatewayFilterFactory<LoginGatewayFilterFactory.Config> {

    // 构造函数
    public LoginGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new OrderedGatewayFilter((exchange, chain) -> {
            // 获取请求request
            ServerHttpRequest request = exchange.getRequest();
            // 获取响应response
            ServerHttpResponse response = exchange.getResponse();


            String path = exchange.getRequest().getURI().getPath();

            // 检查当前路径是否在放行列表中
            if (isPathExcluded(path, config.getExcludePaths())) {
                // 放行路径，直接继续执行
                 return chain.filter(exchange);
            }

            // 非放行路径，验证token
            String token = request.getHeaders().getFirst("token");
            // 如果token为空，或者token过期，则返回未登录错误，否则，重新生成token，并将token返回给前端
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            if (token == null) {
                Mono<Void> voidMono = writeResponse(response, ResponseVO.fail(ResponseEnum.USER_NOT_LOGGED_IN));
                return voidMono;
            }else if(JwtUtil.isExpired(token)){
                Mono<Void> voidMono = writeResponse(response, ResponseVO.fail(ResponseEnum.PERMISSION_EXPIRE));
                return voidMono;
            }else {
                // TODO: 实现token续期逻辑
                // 获取token中的用户信息
                String role= JwtUtil.parseToken(token).get("role",String.class);
                Integer id= JwtUtil.parseToken(token).get("id",Integer.class);
                // 重新生成token
                Map<String,Object> map= new HashMap<>();
                map.put("role",role);
                map.put("id",id);
                String newToken = JwtUtil.generateToken(map);
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    response.getHeaders().set("Authorization", newToken);}));

            }

        }, 0);
    }

    /**
     * 检查路径是否在放行列表中
     */
    private boolean isPathExcluded(String path, List<String> excludePaths) {
        if (excludePaths == null || excludePaths.isEmpty()) {
            return false;
        }

        // 支持通配符匹配，如/login/**
        for (String pattern : excludePaths) {
            if (matchPath(path, pattern)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 路径匹配逻辑，支持**通配符
     */
    private boolean matchPath(String path, String pattern) {
        // 如果模式以**结尾，检查路径是否以模式前缀开头
        if (pattern.endsWith("/**")) {
            String prefix = pattern.substring(0, pattern.length() - 2);
            return path.startsWith(prefix);
        }
        // 如果模式是**，匹配所有路径
        if ("**".equals(pattern)) {
            return true;
        }
        // 精确匹配
        return path.equals(pattern);
    }


    private Mono<Void> writeResponse(ServerHttpResponse response, ResponseVO<?> responseVO) {
        // 设置响应头为JSON格式
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes;
        try {
            // 将responseVO对象转换为JSON格式
            bytes = objectMapper.writeValueAsBytes(responseVO);
        } catch (JsonProcessingException e) {
            // 如果转换失败，则返回IO错误
            return response.writeWith(Mono.error(new IOException()));
        }
        // 将JSON格式写入响应
        return response.writeWith(Mono.just(response.bufferFactory().wrap(bytes)));
    }



    /**
     * 配置类，用于接收配置文件中的参数
     */
    public static class Config {
        // 放行路径列表
        private List<String> excludePaths;

        public List<String> getExcludePaths() {
            return excludePaths;
        }
        public void setExcludePaths(List<String> excludePaths) {
            this.excludePaths = excludePaths;
        }
    }
}
